package com.tianyu.sports.utils;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.util.*;
import org.glassfish.jersey.internal.util.Base64;

/**
 * @author ljj
 * @date 2018/6/27
 */
public class WxRequestUtils {

    /**
     * 微信公众号支付
     * @param totalfee
     * @param userip
     * @param openid
     * @return
     */
    public static Map<String,String> weixinPublicPay(String totalfee,String trade,String userip,String openid){
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        Map<String,String> param = new HashMap<String,String>(11);
        Map<String, String> response = null;
        param.put("appid",Constant.APP_ID);
        param.put("mch_id",Constant.MCH_ID);
        param.put("nonce_str",NonceStr());
        param.put("body",Constant.BODY);
        param.put("out_trade_no",trade);
        param.put("total_fee",String.valueOf(Integer.parseInt(totalfee)*100));
        param.put("spbill_create_ip",userip);
        param.put("notify_url",Constant.URL_NOTIFY);
        param.put("trade_type","JSAPI");
        param.put("openid",openid);
        String xmlInfo = null;
        try {
            xmlInfo = xmlInfo(param);
            System.out.println(xmlInfo);
            String request = httpsRequest (url,"POST",xmlInfo);
            Map map = doXMLParse(request);
            response = new HashMap<String, String>(16);
            //返回给客户端需要的参数
            String prepay_id= (String) map.get("prepay_id");
            String nonce_str= (String) map.get("nonce_str");
            String return_code= (String) map.get("return_code");
            String return_msg= (String) map.get("return_msg");
            Long timeStamp = System.currentTimeMillis() / 1000;
            String stringSignTemp = "appId=" + Constant.APP_ID + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=MD5&timeStamp=" + timeStamp;
            System.out.println("stringSignTemp"+stringSignTemp);
            //再次签名
            String paySign = WxUtil.sign(stringSignTemp, Constant.APP_KEY, "utf-8").toUpperCase();
            //返回页面数据供调用H5使用
            response.put("return_msg", return_msg);
            response.put("return_code", return_code);
            response.put("timeStamp", timeStamp + "");
            response.put("nonceStr", nonce_str);
            response.put("package", "prepay_id=" + prepay_id);
            response.put("appid", Constant.APP_ID);
            response.put("paySign",paySign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response;
    }
    /**
     * 根据订单号查询H5支付信息
     *
     * @param trade
     * @return
     */
    public static Map<String,String> queryOrderByH5Pay(String trade){
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
        Map<String,String> param = new HashMap<String,String>(11);
        Map<String,String> data = null;
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(1,1);
        param.put("appid",Constant.APP_ID);
        param.put("mch_id",Constant.MCH_ID);
        param.put("out_trade_no",trade);
        param.put("nonce_str",NonceStr());
        String xmlInfo = null;
        try {
            xmlInfo = xmlInfo(param);
            String request = httpsRequest (url,"POST",xmlInfo);
            data = doXMLParse(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }
    /**
     * 微信H5支付
     *
     * @param totalfee
     * @param userip
     * @param trade
     * @return
     */
    public static Map<String,String> weixinH5Pay(String totalfee,String userip,String trade){
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        Map<String,String> param = new HashMap<String,String>(11);
        Map<String,String> data = null;
        param.put("appid",Constant.APP_ID);
        param.put("mch_id",Constant.MCH_ID);
        param.put("nonce_str",NonceStr());
        param.put("body",Constant.BODY);
        param.put("out_trade_no",trade);
        param.put("total_fee",String.valueOf(Integer.parseInt(totalfee)*100));
        param.put("spbill_create_ip",userip);
        param.put("notify_url",Constant.URL_NOTIFY);
        param.put("trade_type","MWEB");
        param.put("scene_info","{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"http://www.tianyusports.com\",\"wap_name\": \"天域高尔夫\"}}");
        String xmlInfo = null;
        try {
            xmlInfo = xmlInfo(param);
            String request = httpsRequest (url,"POST",xmlInfo);
            data = doXMLParse(request);
            data.put("ordernumber",trade);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    public static void main(String[] args) {
        SnowflakeIdWorker snowflakeIdWorker = new SnowflakeIdWorker(1,1);
        long order = snowflakeIdWorker.nextId();
        System.out.println(order);
        Map<String, String> stringStringMap = weixinPublicPay("99",String.valueOf(order),"192.168.100.9","oSXaf0aTftipUWIBuK9gZCbfFANM");
        System.out.println(stringStringMap);
    }
    /**
     * 获取随机数
     *
     * @return
     */
    public static String NonceStr(){
        String res = Base64.encodeAsString(Math.random()+"::"+new Date().toString()).substring(0, 32);
        return res;
    }
    /**
     * 获取客户端IP
     *
     * @return
     */
    public static String GetIp() {
        InetAddress ia=null;
        try {
            ia=InetAddress.getLocalHost();
            String localip=ia.getHostAddress();
            return localip;
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * 获取签名
     *
     * @param param
     * @return
     */
    public static String GetSign(Map<String,String> param) {
        String StringA =  Util.formatUrlMap(param, false, false);
        String stringSignTemp= StringA+"&key="+Constant.APP_KEY;
        String Sign = Md5Utils.MD5(stringSignTemp).toUpperCase();
        return Sign;
    }
    /**
     * 将Map转换为XML格式的字符串
     *
     * @param data Map类型数据
     * @return XML格式的字符串
     * @throws Exception
     */
    public static String mapToXml(Map<String, String> data) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder= documentBuilderFactory.newDocumentBuilder();
        org.w3c.dom.Document document = documentBuilder.newDocument();
        org.w3c.dom.Element root = document.createElement("xml");
        document.appendChild(root);
        for (String key: data.keySet()) {
            String value = data.get(key);
            if (value == null) {
                value = "";
            }
            value = value.trim();
            org.w3c.dom.Element filed = document.createElement(key);
            filed.appendChild(document.createTextNode(value));
            root.appendChild(filed);
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMSource source = new DOMSource(document);
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        transformer.transform(source, result);
        String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
        try {
            writer.close();
        }
        catch (Exception ex) {
        }
        return output;
    }

    /**
     * 添加签名并转成xml格式
     * @param param
     * @return
     * @throws Exception
     */
    public static String xmlInfo(Map<String ,String > param) throws Exception {
        String sign = GetSign (param);
        param.put ("sign",sign);
        return mapToXml (param);
    }

    /**
     * 微信统一下单参数设置
     * @param body
     * @param out_trade_no
     * @param total_fee
     * @param openid
     * @return
     * @throws Exception
     */
    public static String WXParamGenerate(String body,String out_trade_no,double total_fee,String openid) throws Exception {
        //价格参数换算成分
        int fee = (int)(total_fee * 100.00);
        Map<String,String> param = new HashMap<String,String>();
        param.put("appid", Constant.APP_ID);
        param.put("mch_id", Constant.MCH_ID);
        param.put("nonce_str",NonceStr());
        param.put("body", body);
        param.put("out_trade_no",out_trade_no);
        param.put("total_fee", fee+"");
        param.put("spbill_create_ip", GetIp());
        param.put("notify_url", Constant.URL_NOTIFY);
        param.put("openid",openid);
        param.put("trade_type", "JSAPI");

        String sign = GetSign(param);
        param.put("sign", sign);
        return mapToXml(param);
    }

    /**
     * 发起微信支付请求接口
     *
     * @param requestUrl
     * @param requestMethod
     * @param outputStr
     * @return
     */
    public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        try {
            URL url = new URL(requestUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            conn.setRequestMethod(requestMethod);
            conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
            // 当outputStr不为null时向输出流写数据
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意编码格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }
            // 从输入流读取返回内容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            // 释放资源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            return buffer.toString();
        } catch (ConnectException ce) {
            System.out.println("连接超时：{}"+ ce);
        } catch (Exception e) {
            System.out.println("https请求异常：{}"+ e);
        }
        return null;
    }

    /**
     * xml解析
     *
     * @param strxml
     * @return
     * @throws Exception
     */
    public static Map<String, String> doXMLParse(String strxml) throws Exception {
        strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
        if(null == strxml || "".equals(strxml)) {
            return null;
        }
        Map<String,String> m = new HashMap<String,String>();
        InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
        SAXBuilder builder = new SAXBuilder();
        Document doc = builder.build(in);
        Element root = doc.getRootElement();
        List list = root.getChildren();
        Iterator it = list.iterator();
        while(it.hasNext()) {
            Element e = (Element) it.next();
            String k = e.getName();
            String v = "";
            List children = e.getChildren();
            if(children.isEmpty()) {
                v = e.getTextNormalize();
            } else {
                v = getChildrenText(children);
            }
            m.put(k, v);
        }
        //关闭流
        in.close();
        return m;
    }

    /**
     * 获取子文本
     *
     * @param children
     * @return
     */
    public static String getChildrenText(List children) {
        StringBuffer sb = new StringBuffer();
        if(!children.isEmpty()) {
            Iterator it = children.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String name = e.getName();
                String value = e.getTextNormalize();
                List list = e.getChildren();
                sb.append("<" + name + ">");
                if(!list.isEmpty()) {
                    sb.append(getChildrenText(list));
                }
                sb.append(value);
                sb.append("</" + name + ">");
            }
        }
        return sb.toString();
    }

}
